package io.github.source.media.bean;


import com.google.gson.annotations.SerializedName;

import java.io.Serializable;
import java.util.List;

import androidx.annotation.Nullable;


/**
 * 媒体查询结果类，用于封装查询操作的结果信息。
 */
@SuppressWarnings("unused")
public final class MediaResult<T> implements Serializable {

    /**
     * 成功的结果。
     *
     * @param body 结果数据。
     * @param <T>  结果数据的类型。
     * @return MediaResult实例。
     */
    public static <T> MediaResult<T> success(@Nullable T body) {
        return new MediaResult<>(MediaCode.SUCCESS, null, body);
    }

    /**
     * 成功的结果，包含原始响应数据。
     *
     * @param raw  原始响应数据。
     * @param body 结果数据。
     * @param <T>  结果数据的类型。
     * @return MediaResult实例。
     */
    public static <T> MediaResult<T> success(Object raw, @Nullable T body) {
        return new MediaResult<>(MediaCode.SUCCESS, raw, body);
    }

    /**
     * 空结果，表示未找到数据。
     *
     * @param <T> 结果数据的类型。
     * @return MediaResult实例。
     */
    public static <T> MediaResult<T> empty() {
        return error(MediaCode.NOT_FOUND);
    }

    /**
     * 错误的结果，根据错误码创建。
     *
     * @param code 错误码。
     * @param <T>  结果数据的类型。
     * @return MediaResult实例。
     * @throws IllegalArgumentException 如果错误码小于400。
     */
    public static <T> MediaResult<T> error(int code) {
        if (code < 400) {
            throw new IllegalArgumentException("code < 400: " + code);
        }
        return new MediaResult<>(code, null, null);
    }

    /**
     * 错误的结果，根据错误码和数据创建。
     *
     * @param code 错误码。
     * @param body 错误数据。
     * @param <T>  结果数据的类型。
     * @return MediaResult实例。
     * @throws IllegalArgumentException 如果错误码小于400。
     */
    public static <T> MediaResult<T> error(int code, @Nullable T body) {
        if (code < 400) {
            throw new IllegalArgumentException("code < 400: " + code);
        }
        return new MediaResult<>(code, null, body);
    }

    /**
     * 根据异常创建错误的结果。
     *
     * @param throwable 异常对象。
     * @param <T>       结果数据的类型。
     * @return MediaResult实例。
     */
    public static <T> MediaResult<T> error(Throwable throwable) {
        MediaResult<T> result = new MediaResult<>(500, null, null);
        result.setMessage(throwable.getMessage());
        return result;
    }


    public static <T> MediaResult<T> error(String msg) {
        MediaResult<T> result = new MediaResult<>(500, null, null);
        result.setMessage(msg);
        return result;
    }

    private MediaResult(
            int code, Object rawResponse, @Nullable T body) {
        this.code = code;
        this.rawResponse = rawResponse;
        this.data = body;
    }

    /**
     * 数据
     */
    @SerializedName("data")
    private @Nullable T data;
    /**
     * 结果码
     */
    @SerializedName("code")
    int code;
    /**
     * 消息
     */
    @SerializedName("message")
    String message;
    /**
     * 时间戳
     */
    @SerializedName("time")
    long time;

    /**
     * 通过Class将数据转换到具体类
     */
    private List<Class> types;
    /**
     * 源数据，来自于最初始的数据，以字符串存在
     */
    private List<Object> rawStr;

    /**
     * 已转转成的Object对象，它可以0个，多个. 它们的类型可通过types转对应强转
     */
    private List<Object> list;
    private Object rawResponse;

    // The revised 'code' method, assuming 'this' is indeed an instance of MediaResult<T>
    public MediaResult<T> code(int code) {
        this.code = code; // Directly setting the field, assuming this is intended behavior
        return this; // No need for a cast since we're within the MediaResult class
    }

    // Example of a 'data' method to maintain the chaining capability
    public MediaResult<T> data(T data) {
        this.data = data;
        return this;
    }

    public <T> MediaResult<T> raw(Object raw) {
        this.rawResponse = raw;
        return (MediaResult<T>) this;
    }

    public <T> MediaResult<T> message(String message) {
        this.message = message;
        return (MediaResult<T>) this;
    }

    public <T> MediaResult<T> types(List<Class> classes) {
        this.types = classes;
        return (MediaResult<T>) this;
    }

    @Nullable
    public T getData() {
        return data;
    }

    @Nullable
    public void setData(T data) {
        this.data = data;
    }

    public int getCode() {
        return code;
    }


    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public long getTime() {
        return time;
    }

    @Override
    public String toString() {
        return "MediaResult{" +
                "data=" + data +
                ", code=" + code +
                ", message='" + message + '\'' +
                ", time=" + time +
                ", types=" + types +
                ", rawStr=" + rawStr +
                ", list=" + list +
                ", rawResponse=" + rawResponse +
                '}';
    }
}